﻿using MongoDB.Driver;
using System.Collections.Generic;
using System.Linq;

namespace nMongo
{
    public partial class MongoEngine
    {
        #region Insert one (3 overloads)
        /// <summary>
        /// Stores an object in the current collection.
        /// </summary>
        /// <param name="oneObject">Object to be stored.</param>
        /// <returns>bool: if the object was been stored with success; false: if the object was not been stored with success.</returns>
        public virtual bool Insert<T>(T oneObject)
            where T : class
        {
            WriteConcernResult result;
            return this.Insert<T>(oneObject, out result);
        }

        /// <summary>
        /// Stores an object in the current collection.
        /// </summary>
        /// <param name="oneObject">Object to be stored.</param>
        /// <param name="result">WriteConcernResult object to receive the operation result.</param>
        /// <returns>bool: if the object was been stored with success; false: if the object was not been stored with success.</returns>
        public virtual bool Insert<T>(T oneObject, out WriteConcernResult result)
            where T : class
        {
            return this.Insert<T>(oneObject, WriteConcern.Acknowledged, out result);
        }

        /// <summary>
        /// Stores an object in the current collection.
        /// </summary>
        /// <param name="oneObject">Object to be stored.</param>
        /// <param name="concern">Type of WriteConcern to be acknownledged.</param>
        /// <param name="oneObject">Object to be stored.</param>
        /// <returns>bool: if the object was been stored with success; false: if the object was not been stored with success.</returns>
        public virtual bool Insert<T>(T oneObject, WriteConcern concern, out WriteConcernResult result)
            where T : class
        {
            result = this.Database.GetCollectionFromType<T>().Insert(oneObject, concern);
            bool returned = result != null && result.Ok;

            //if (returned)
            //{
            //    this.AutoDetectPersistencyByObject(MongoPersistencyState.Saved, oneObject);
            //}
            return returned;
        } 
        #endregion

        #region Insert multiple (3 overloads)
        /// <summary>
        /// Stores a list of objects inside the current collection.
        /// </summary>
        /// <param name="objects">List of objects to be stored.</param>
        /// <returns>IEnumerable(T): a collection of the successful insert operations and the objects saved with identity.</returns>
        public virtual IEnumerable<T> Insert<T>(IEnumerable<T> objects)
            where T : class
        {
            IDictionary<T, WriteConcernResult> results;
            return this.Insert<T>(objects, out results);
        }

        /// <summary>
        /// Stores a list of objects inside the current collection.
        /// </summary>
        /// <param name="objects">List of objects to be stored.</param>
        /// <param name="results">(IDictionary(T, WriteConcernResult)): the delete results dictionary, where the key is the object for an insert operation and the value is the WriteConcernResult object with the operation results.</param>
        /// <returns>IEnumerable(T): a collection of the successful insert operations and the objects saved with identity.</returns>
        public virtual IEnumerable<T> Insert<T>(IEnumerable<T> objects, out IDictionary<T, WriteConcernResult> results)
            where T : class
        {
            return this.Insert<T>(objects, WriteConcern.Acknowledged, out results);
        }

        /// <summary>
        /// Stores a list of objects inside the current collection.
        /// </summary>
        /// <param name="objects">List of objects to be stored.</param>
        /// <param name="concern">Type of WriteConcern to be acknownledged.</param>
        /// <param name="results">(IDictionary(T, WriteConcernResult)): the delete results dictionary, where the key is the object for an insert operation and the value is the WriteConcernResult object with the operation results.</param>
        /// <returns>IEnumerable(T): a collection of the successful insert operations and the objects saved with identity.</returns>
        public virtual IEnumerable<T> Insert<T>(IEnumerable<T> objects, WriteConcern concern, out IDictionary<T, WriteConcernResult> results)
            where T : class
        {
            results = new Dictionary<T, WriteConcernResult>();
            using (this.Database.RequestStart())
            {
                foreach (T singleObject in objects)
                {
                    WriteConcernResult result;
                    this.Insert(singleObject, concern, out result);
                    results.Add(singleObject, result);
                }
            }
            return results.Where(x => x.Value.Ok).Select(x => x.Key);
        } 
        #endregion
    }
}
